package edu.gatech.doi.spamframework.mapping;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.jdom.Element;
import org.jdom.JDOMException;

import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ArffSaver;

import edu.gatech.doi.spamframework.core.MappingXMLFiles;
import edu.gatech.doi.spamframework.core.ModelXMLFiles;
import edu.gatech.doi.spamframework.model.Message;
import edu.gatech.doi.spamframework.model.ModelAttribute;

import edu.gatech.doi.spamframework.model.XMLOperator;


public class ZingMapper implements Mapper {

	private String modelsdirectory=System.getProperties().getProperty("user.dir")+System.getProperties().getProperty("file.separator")+"models"+System.getProperties().getProperty("file.separator");
	private String instancesdirectory=System.getProperties().getProperty("user.dir")+System.getProperties().getProperty("file.separator")+"instances"+System.getProperties().getProperty("file.separator");
	
	private String datasetsdirectory=System.getProperties().getProperty("user.dir")+System.getProperties().getProperty("file.separator")+"datasets"+System.getProperties().getProperty("file.separator")+"Zing"+System.getProperties().getProperty("file.separator");
	
	
	private String mappingsdirectory=System.getProperties().getProperty("user.dir")+System.getProperties().getProperty("file.separator")+"mappings"+System.getProperties().getProperty("file.separator");
	private String propertiesdirectory=System.getProperties().getProperty("user.dir")+System.getProperties().getProperty("file.separator")+"properties"+System.getProperties().getProperty("file.separator");
	
	private String personmodelfilename="personmodel.xml";
	
	private String messagemodelfilename="messagemodel.xml";
	
	private String personmappingfilename="zingpersonmapping.xml";
	private String messagemappingfilename="zingmessagemapping.xml";
	
	private HashMap personmodelhm;
	
	private HashMap personmappinghm;
	
	private HashMap messagemodelhm;
	
	private HashMap messagemappinghm;
	private String zingpersonarfffilename;
	

	//0: append; 1: replace
	private int isappended=0;
	
	
	public void init()
	{	
		// load property file for myspace
		
		String filepath0=this.propertiesdirectory+"zing.properties";
//		System.out.println(filepath0);
		PropertiesFileOperator pfo=new PropertiesFileOperator(filepath0);
		pfo.load();
		HashMap mhm=ModelXMLFiles.getMap();
		HashMap mappinghm=MappingXMLFiles.getMap("ZING");
		this.messagemodelfilename=(String) mhm.get("MESSAGE");
		this.personmappingfilename=(String) mappinghm.get("ZING.PERSON");
		this.personmodelfilename=(String) mhm.get("PERSON");
		this.zingpersonarfffilename=pfo.getProperty("PERSONARFF");
		this.isappended=Integer.parseInt(pfo.getProperty("ISAPPENDED"));
//		System.out.println(this.messagemodelfilename+" "+this.personmappingfilename+" "+this.personmodelfilename);
		
		// load models and mappings
		XMLOperator xmlo=new XMLOperator();
		//person models
		String filepath1=this.modelsdirectory+this.personmodelfilename;
		this.personmodelhm=new HashMap();
//		System.out.println("filepath:"+filepath);
		this.personmodelhm=xmlo.getModelAttrsFromXML(filepath1);
//		if(this.personmodelhm==null)
//		{
//			System.out.println("personmappinghm is null");
//		}
		String filepath2=this.mappingsdirectory+this.personmappingfilename;
		this.personmappinghm=new HashMap();
		this.personmappinghm=xmlo.getMappingAttrsFromXML(filepath2);
//		this.zingarfffilename="zingperson.arff";
		//message models
		
		
		
	}
	
	public void parseMessagesFromIndexFile(String indexFileName)
	{
		File file=new File(indexFileName);
		
		if(file.exists())
		{
			try {
				FileReader fis=new FileReader(file);
				BufferedReader bis=new BufferedReader(fis);
				String line;
				while((line=bis.readLine())!=null)
				{
					this.parseMessages(line);
				}
				
				
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else
		{
			System.out.println("Index File does not exist!!!");
			
		}
		
	}
	public void parsePersonsFromIndexFile(String indexFileName)
	{
		File file=new File(indexFileName);
		
		if(file.exists())
		{
			try {
				FileReader fis=new FileReader(file);
				BufferedReader bis=new BufferedReader(fis);
				String line;
				while((line=bis.readLine())!=null)
				{
					this.parsePersons(line);
				}
				
				
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else
		{
			System.out.println("Index File does not exist!!!");
			
		}
	}
	
	@Override
	public Instances parsePersons(String personFile) {
		// TODO Auto-generated method stub
		
		Instances       data = null;
		FastVector      atts;
		
		ArrayList attributelist=new ArrayList();
		/**
		 * userid,username,gender,dob,height,weight,countryid,cityid
		 */
//		attributelist.add("USERID");
//		attributelist.add("USERNAME");
//		attributelist.add("GENDER");
//		attributelist.add("DOB");
//		attributelist.add("HEIGHT");
//		attributelist.add("WEIGHT");
//		attributelist.add("COUNTRYID");
//		attributelist.add("CITYID");	
		
		Iterator attrit=this.personmappinghm.keySet().iterator();
		
		HashMap mappingattrhm=new HashMap();
		
		while(attrit.hasNext())
		{
			String tempattrstr=(String) attrit.next();
			attributelist.add(tempattrstr);
			MappingAttribute mappinga=(MappingAttribute) this.personmappinghm.get(tempattrstr);
			mappingattrhm.put(mappinga.getModelAttributeName(), mappinga);
		}
		
		// 1. set up attributes
		 atts = new FastVector();
		 /**
			 * userid,username,gender,dob,height,weight,countryid,cityid
			 */
		    
		 	Set personmodelkeyset= this.personmodelhm.keySet();
		 	List list=new ArrayList(personmodelkeyset);
		 	Collections.sort(list);
		    Iterator it=list.iterator();
		    while(it.hasNext())
		    {
		    	String tempstr=(String)it.next();
//		    	System.out.println("tempstr1="+tempstr);
		    	ModelAttribute attribute=(ModelAttribute) this.personmodelhm.get(tempstr.trim());
		    	String attributename=attribute.getAttributeName();
//		    	System.out.println("attributename:"+attributename);
		    	int typeid=attribute.getAttributeTypeId();
		    	
		    	switch(typeid)
		    	{
		    	case 1:
		    		//-numeric
		    		
		    		atts.addElement(new Attribute(attributename));
		    		break;
		    	case 2:
		    		//-nominal
		    		FastVector attVals;
		    	    attVals = new FastVector();
		    	    ArrayList al=attribute.getNomialValues();
		    	    Iterator ital=al.iterator();
		    	    while(ital.hasNext())
		    	    {
		    	    	String alstr=(String) ital.next();
		    	    	attVals.addElement(alstr);
		    	    }
		    	    atts.addElement(new Attribute(attributename, attVals));
		    	    break;
		    		
		    	case 3:
		    		//-string
		    		atts.addElement(new Attribute(attributename, (FastVector) null));
		    		break;
		    	case 4:
		    		//-date
		    	    atts.addElement(new Attribute(attributename, (FastVector) null));
		    	    break;
		    	}
		    }
		    // 2. create Instances object
		    
		    data = new Instances("ZingPersons", atts, 0);
		    
		    //save attributes and relation to the files.
		    File file=new File(personFile);
		    
		    //create file
			String arfffilename=this.instancesdirectory+this.zingpersonarfffilename;   
		    File arfffile=new File(arfffilename);
		    if(!arfffile.exists())
		    {
		    	try {
		    		arfffile.createNewFile();
				 	this.save2arff(data, this.instancesdirectory, this.zingpersonarfffilename);
	 
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		    }
		    else
		    {
		    	try {
			    	if(this.isappended==1)
		    		{
						arfffile.delete();
						arfffile.createNewFile();
					 	this.save2arff(data, this.instancesdirectory, this.zingpersonarfffilename);
		    		}
		    	
	    		} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		    }
		    FileWriter writer = null;
		    BufferedWriter bw=null;
			
		    // 3. fill with data
		    
		    //read the flat files
		    HashMap hm=this.personMapping(attributelist);
		    
		    
		    
		    BufferedReader input = null;
			
			try {
				input = new BufferedReader(new FileReader(personFile));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		
		    String line = null; //not declared within while loop
	        /*
	        * readLine is a bit quirky :
	        * it returns the content of a line MINUS the newline.
	        * it returns null only for the END of the stream.
	        * it returns an empty String if two newlines appear in a row.
	        */
		   
		    int num=0;
	        try {
				while (( line = input.readLine()) != null){
					 HashMap inhm=new HashMap();
					/**
					 * 1.userid,2.username,3.gender,4.dob,5.height,6.weight,11.countryid,12.cityid,13. income, 14,education_id, 15. job_id
					 */
					String[] linesubstrs=line.split(";");
//					System.out.println(linesubstrs.toString()+" length:"+linesubstrs.length);
					HashMap linehm=new HashMap();
					
					linehm.put("USERID", linesubstrs[0]);
					linehm.put("USERNAME", linesubstrs[1]);
					linehm.put("GENDER", linesubstrs[2]);
					linehm.put("DOB", linesubstrs[3]);
					linehm.put("HEIGHT", linesubstrs[4]);
					linehm.put("WEIGHT", linesubstrs[5]);
					linehm.put("COUNTRYID", linesubstrs[10]);
					linehm.put("CITYID", linesubstrs[11]);
					linehm.put("INCOME", linesubstrs[12]);
					linehm.put("EDUCATION_ID", linesubstrs[13]);
					linehm.put("JOB_ID", linesubstrs[14]);
					
					
						Iterator it1=attributelist.iterator();
						while(it1.hasNext())
						{
							String attstr=(String)it1.next();
							String rows = null;
							
							rows=(String) linehm.get(attstr);
							ModelAttribute attribute=(ModelAttribute)hm.get(attstr);
					    	String attributename=attribute.getAttributeName();
							inhm.put(attributename.trim(), rows);
//					System.out.println("child:"+attributename.trim()+": "+rows);
						}
					    Instance newInst = new Instance(data.numAttributes());

						for(int i=0;i<data.numAttributes();i++)
						{
//					System.out.println("i="+data.numAttributes());
							if(inhm.containsKey(data.attribute(i).name()))
							{
								System.out.println(data.attribute(i).name());
							 //-numeric
							   if(data.attribute(i).isNumeric())
							   {
								   newInst.setValue(data.attribute(i),Double.valueOf((String) inhm.get(data.attribute(i).name())));
								   
							   }
							   //-nominal
							   if(data.attribute(i).isNominal())
							   {
								   
//								   this.personmappinghm.get(key);
								   MappingAttribute mapa=(MappingAttribute) mappingattrhm.get(data.attribute(i).name());
								   ModelAttribute modela=(ModelAttribute) hm.get(mapa.getAttributeName());
								   String tempstr=(String) inhm.get(data.attribute(i).name());
								   ArrayList modelal=modela.getNomialValues();
								   ArrayList mappingal=mapa.getNomialValues();
								   HashMap mappingnominal=new HashMap();
								   for(int n=0;n<modelal.size();n++)
								   {
//									   System.out.println("mapping:"+mappingal.get(n)+ modelal.get(n));
									   mappingnominal.put(mappingal.get(n), modelal.get(n));
								   }
								   
								   newInst.setValue(data.attribute(i),(String)mappingnominal.get(tempstr));
							   }
							   //-string
							   if(data.attribute(i).isString())
							   {
//						   System.out.println("--"+data.attribute(i).name());
								   String tempstr=(String)inhm.get(data.attribute(i).name());
//						   System.out.println(tempstr);
								  
								   newInst.setValue(data.attribute(i),tempstr);
									
//						   vals[i] = data.attribute(i).addStringValue("This is a string!");
							   }
						   
							   //-date
							   if(data.attribute(i).isDate())
							   {
								   newInst.setValue(data.attribute(i),(String) inhm.get(data.attribute(i).name()) );
									
//						   try {
//							vals[i] = data.attribute(i).parseDate("2001-11-09");
//						} catch (ParseException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						}
							   }
							}
						}
						
						
						//instanceid;
//				System.out.println(personFile);


//				System.out.println("index1"+index1+" index2:"+index2);
						String instanceidstr="Zing_"+linehm.get("USERID");
						
						newInst.setValue(data.attribute(data.numAttributes()-2), instanceidstr);
						// add
					     data.add(newInst);
					    
					     //append new instance to the file
		 			    	
		 			    	writer =new FileWriter(arfffilename, true);
		 			    	
		 				    bw=new BufferedWriter(writer);
		 				    try {
		 				    	
		 				    	  // You are now at the end of the file,
		 				    	  // and can start writing new data out, e.g.
		 				    	 bw.newLine(); 
		 				    	 for(int i=0;i<data.numInstances();i++)
		 				    	 {
		 				    		 bw.write(data.instance(i).toString());
		 				    		 bw.newLine();
		 				    		 bw.flush();
		 				    	 }
		 				    	 bw.close();
		 				    	 writer.close();
		 				    	 bw=null;
		 				    	 writer=null;
		 				    	} catch (IOException ex ) {
		 				    	  ex.printStackTrace();
		 				    	}finally {                       // always close the file
		 				    		 if (bw != null) try {
		 				    		    bw.close();
		 				    		 } catch (IOException ioe2) {
		 				    		    // just ignore it
		 				    		 }
		 				    	 }
		 				    	// delete instances in data
		 				    data.delete();
					     num++;
					     System.out.println(num);
				    	
				    }
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}



		  
		    
		  return data;
	}

	@Override
	public Instances parseMessages(String msgFile) {
		// TODO Auto-generated method stub
		return null;
	}
	
/**
 * attributes mapping
 * @param attr
 * @return
 */
	public HashMap personMapping(ArrayList attr)
	{
		
		HashMap hm=new HashMap();
		Iterator it=attr.iterator();
		while(it.hasNext())
		{
			String tempstr=(String) it.next();
//			System.out.println("personMapping tempstr="+tempstr);
			/**
			 * userid,username,gender,dob,height,weight,countryid,cityid
			 */
			MappingAttribute maa=(MappingAttribute)(this.personmappinghm.get(tempstr));
			String modelattributename=maa.getModelAttributeName();
//			System.out.println("modelattributename:"+modelattributename);
			ModelAttribute ma=(ModelAttribute)this.personmodelhm.get(modelattributename);

//			System.out.println("ma.getattributename:"+ma.getAttributeName());
			hm.put(tempstr,ma);
		}
		return hm;
			
		
		
	}
	
	/**
	 * attributes mapping
	 * @return
	 */
	public HashMap messageMapping()
	{
		return null;
	}
	

	
	/**
	 * save instances to arff files
	 * @param in
	 * @param filedirectory
	 * @param filename
	 */
	public void save2arff(Instances in, String filedirectory, String filename)
	{
		 Instances dataSet =in;
		 ArffSaver saver = new ArffSaver();
		 saver.setInstances(dataSet);
		 try {
			saver.setFile(new File(filedirectory+System.getProperties().getProperty("file.separator")+filename));
		//	saver.setDestination(new File("./data/test.arff"));   // **not** necessary in 3.5.4 and later
			 saver.writeBatch();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 
	}
	
	
	public int getIsappended() {
		return isappended;
	}



	public void setIsappended(int isappended) {
		this.isappended = isappended;
	}



	public static void main(String [] arg0)
	{
		ZingMapper zm=new ZingMapper();
		String personFile=zm.datasetsdirectory+"profiletest.txt";
//		zm.setIsappended(0);
		zm.init();
		Instances ins=zm.parsePersons(personFile);
//		msm.save2arff(ins, msm.getInstancesdirectory(), "test1.arff");
	}
}
